const Common=require('../util/common');
const queue = require('queue');
const TimerManager=require('./TimerManager');
//房间
class Room{
    constructor(options,docker){
        this.docker=docker;
        this.roomId=0;
        this.type=0; //0为乱斗模式 1为组队模式
        this.roomType=0; //0为随机乱斗  1组队匹配  2好友对抗
        this.queue=queue({autostart:true});
        this.queue.pushTry=function(fun){
            this.queue.push(function(){
                try{
                    this.fun();
                }catch(e){
                    console.error(e);
                    const mongoose = require('mongoose');
                    const ErrorModel=mongoose.models['Error'];
                    ErrorModel.create({
                        stack:JSON.stringify(e.stack)
                    });
                }
            }.bind({fun:fun}))
        }.bind(this);
        this.timerManager=new TimerManager();
        Object.assign(this,options);
        this.status=0; //0房间创建完毕，1玩家全部载入游戏准备好，游戏正式开始
        this.users=[]; //用户
        this.bombs=[]; //泡泡
        this.currentBombId=0;  //泡泡ID
        this.map=null; //游戏地图
        this.currentPorpertyId=0;
        this.isGameOver=false;
        this.properties=[];  //道具
        this.createTime=new Date().getTime(); //房间创建事件，用于容器定期清理超时房间
        this.endTime=0; //结束时间
        //箱子炸毁产生的物品权重
        this.weightProperty=[{type:0,weight:20},{type:1,weight:20},{type:2,weight:20},{type:3,weight:1}];
    }
    getMessage(){
        let obj={
            roomId:this.roomId,
            type:this.type,
            roomType:this.roomType,
            status:this.status,
            users:[],
            map:this.map.getMessage(),
            bombs:[],
            properties:[]
        };
        for(let i=0;i<this.bombs.length;i++){
            obj.bombs.push(this.bombs[i].getMessage());
        }
        for(let i=0;i<this.users.length;i++){
            obj.users.push(this.users[i].getMessage());
        }
        for(let i=0;i<this.properties.length;i++){
            obj.properties.push(this.properties[i].getMessage());
        }
        return obj;
    }
    //大乱斗游戏开始
    async gameStart(){
        let mapRandomIndex=Math.floor(Math.random()*4);
        let userCount=this.users.length;
        if(userCount<2){
            return;
        }
        if(userCount%2!==0){ //如果人数为单数，则自动选择多一人的地图
            userCount++;
        }
        let Map=require(`./map/${userCount}_${mapRandomIndex}`);
        // let Map=require(`./map/2_1`);
        this.map=new Map();
        //打乱玩家顺序
        this.map.userStartPos.sort(()=>{
            return Math.random()-0.5;
        });
        //给玩家赋值初始坐标
        for(let i=0;i<this.users.length;i++){
            this.users[i].upX=this.map.userStartPos[i][0];
            this.users[i].upY=this.map.userStartPos[i][1];
            this.users[i].x=this.map.userStartPos[i][0];
            this.users[i].y=this.map.userStartPos[i][1];
            this.users[i].gameStartAdd();
            await this.users[i].gameStartReduce();
        }
        this.broadcastGameStart();
        //自动进入准备状态
        this.readyTimer=this.timerManager.setTimeout(function(){
            this.docker.queue.pushTry(function(){
                for(let i=0;i<this.users.length;i++){
                    this.users[i].ready();
                }
            }.bind(this));
        }.bind(this),15000);
    }
    //检测游戏是否结束
    checkGameOver(){
        //找出幸存者
        let aliveUser=this.users.find(item=>{return item.status!==-1});
        if(!aliveUser){ //如果没有幸存者，则游戏结束
            this.gameOver();
            return;
        }
        //判断是否有第一个幸存者分组以外的幸存者
        let otherAliveUser=this.users.find(item=>{return item.status!==-1&&item.group!==aliveUser.group});
        if(!otherAliveUser){
            this.gameOver();
        }
    }
    //游戏结束
    async gameOver(){
        this.endTime=new Date().getTime();
        let aliveUser=this.users.find(item=>{return item.status!==-1});
        let result=[];
        if(!aliveUser) { //如果没有幸存者，则游戏平局结束
            if(this.type==1){ //如果是分组对抗，则都是平局
                for(let i=0;i<this.users.length;i++){
                    this.users[i].result=0;
                    this.users[i].getTieReward();
                }
            }else{
                let now=new Date().getTime();
                let tieUsers=this.users.filter(item=>{return now-item.dieTimeTick<1000});
                let failUsers=this.users.filter(item=>{return now-item.dieTimeTick>=1000});
                //发放平局奖励
                for(let i=0;i<tieUsers.length;i++){
                    tieUsers[i].result=0;
                    tieUsers[i].getTieReward();
                }
                //已经提前死亡的用户发放死亡奖励
                for(let i=0;i<failUsers.length;i++){
                    failUsers[i].result=-1;
                    failUsers[i].getFailReward();
                }
            }
        }else {
            //发放胜利，失败者的奖励
            for(let i=0;i<this.users.length;i++){
                if(this.users[i].group==aliveUser.group){
                    this.users[i].result=1;
                    this.users[i].getWinReward();
                }else{
                    this.users[i].result=-1;
                    this.users[i].getFailReward();
                }
            }
            //this.broadcastEvent('gameOver',{winGroup:aliveUser.group});
        }
        for(let i=0;i<this.users.length;i++){
            // await this.users[i]._receiveRewards();
            let score = 0;
            let winCountScore = this.users[i].winCount > 4 ? 4 : this.users[i].winCount;
            if(this.type == 0){
                let len = this.users.length;
                if(this.users[i].result == 1){
                    score = len + 1 + winCountScore;
                }
                else if(this.users[i].result == -1){
                    score = len == 6 ? -2 : (len - 7);
                }
            }
            else if(this.type == 1){
                score = this.users[i].result == -1 ? -3 : 3;
                if(score > 0) score += winCountScore + 1;
            }
            result.push({_id:this.users[i]._id,index:this.users[i].index,win:this.users[i].result,changeLevel:score, winCount: score > 0 ? this.users[i].winCount + 1 : 0});
        }
        if(this.roomType===1){
            this.broadcastEvent('gameOver',{result:result,win:5,lose:-5});
        }else{
            this.broadcastEvent('gameOver',{result:result,win:5,lose:-2});
        }
        this.isGameOver=true;
        this.clear();
        this.queue.end();
        this.queue.autostart=false;
        //开始计算段位,只有随机乱斗才有段位计算
        if(this.roomType===0||this.roomType===1){
            await this.calculateLevel(result);
        }
        //保存房间信息到记录数据库
        //await this.saveRecord();
        //处理任务模块
        //await this.doMission(result);
        //处理玩家是否第一次进行过游戏
        await this.doIsPlayGame(result);
    }
    //处理玩家是否进行过游戏
    async doIsPlayGame(result){
        const mongoose=require('mongoose');
        let GameUserModel=mongoose.models['GameUser'];
        for(let i=0;i<result.length;i++){
            let user=this.docker.users[result[i]._id];
            let gameUser=await GameUserModel.findById(user._id);
            if(!!gameUser && !gameUser.ppt_isPlayGame){
                gameUser.ppt_isPlayGame=true;
                await gameUser.save();
            }
        }
    }
    //处理任务模块
    async doMission(result){
        const mongoose=require('mongoose');
        let GameUserModel=mongoose.models['GameUser'];
        for(let i=0;i<result.length;i++){
            let user=this.docker.users[result[i]._id];
            let gameUser=await GameUserModel.findById(user._id);
            //连赢任务
            if(result[i].win===1){
                gameUser.mission.doOneMission(3);
            }else{
                gameUser.mission.resetOneMission(3);
            }
            //好友对抗任务
            if(this.roomType===2){
                gameUser.mission.doOneMission(4);
            }
            //随机乱斗任务
            if(this.roomType===0){
                gameUser.mission.doOneMission(5);
            }
            let now=new Date();
            //早自习任务
            if(now.getHours()==6||now.getHours()==7){
                gameUser.mission.doOneMission(6);
            }
            //晚自习任务
            if(now.getHours()==22||now.getHours()==23){
                gameUser.mission.doOneMission(7);
            }
            await gameUser.save();
        }

    }
    //保存房间记录到数据库
    async saveRecord(){
        // const mongoose=require('mongoose');
        // let RecordModel=mongoose.models['Record'];
        // await RecordModel.create(this);
    }
    //根据游戏结果计算段位奖励
    async calculateLevel(result){
        const mongoose=require('mongoose');
        let GameUserModel=mongoose.models['GameUser'];
        for(let i=0;i<result.length;i++){
            let user=this.docker.users[result[i]._id];
            if(user.isBot){ //机器人不计算段位
                continue;
            }
            let gameUser=await GameUserModel.findById(user._id);
            if(result[i].win===1){
                if(!!gameUser){
                    gameUser.winCount += 1;
                    gameUser.levelUp(result[i].changeLevel);
                    user.level = gameUser.level;
                }
            }
            if(result[i].win===-1){
                if(!!gameUser){
                    gameUser.winCount = 0;
                    gameUser.levelDown(Math.abs(result[i].changeLevel));
                    user.level = gameUser.level;
                }
            }
            // gameUser.task.checkGameFinish(this.roomType,result[i].win)
            //给用户增加在线时长记录
            //await gameUser.addOnlineTime(this.endTime-this.createTime);
            await gameUser.save();
        }
    }
    //某个泡泡开始爆炸
    bomb(i){
        let bombs=[];
        let destroyBoxes=[]; //需要被摧毁的箱子
        let properties=[]; //箱子被炸毁产生的道具
        let bombArea=[]; //产生爆炸的点
        let bomb=this.bombs.find(item=>{return item.i==i});
        if(!!bomb){
            bomb.bomb(bombs,destroyBoxes,bombArea);
        }
        //在地图中销毁需要销毁的箱子
        for(let i=0;i<destroyBoxes.length;i++){
            this.destroyBox(destroyBoxes[i][1],destroyBoxes[i][0],properties);
        }
        for(i=0;i<this.users.length;i++){
            this.users[i].sendBombChange({bombs:bombs,destroyBoxes:destroyBoxes,properties:properties});
        }
        //this.broadcastEvent('bomb',{bombs:bombs,destroyBoxes:destroyBoxes,properties:properties});
        this.checkBombUser(bombArea);
    }
    //判断爆炸点数组是否有该用户，如果有，则泡住
    checkBombUser(bombArea){
        for(let i=0;i<this.users.length;i++){
            if(bombArea.findIndex(item=>{return item[0]===this.users[i].x&&item[1]===this.users[i].y})>=0){
                if(this.users[i].status===0){
                    this.users[i].beBomb();
                }else if(this.users[i].status===10){
                    this.users[i].die();
                }
            }
        }
    }
    //炸毁一个箱子
    destroyBox(y,x,properties){
        this.map.boxes[y][x]=0;
        let randomNumber=Math.floor(100*Math.random());
        //30%几率产生道具
        if(randomNumber<30){
            let weightRandom=Common.weightRandom(this.weightProperty);
            const Property=require('./Property');
            let property=new Property({i:this.currentPorpertyId,x:x,y:y,type:weightRandom.type},this);
            this.properties.push(property);
            properties.push(property.getMessage());
            this.currentPorpertyId++;
        }
    }

    clear(){
        for(let i=0;i<this.users.length;i++){
            this.users[i].reset();
        }
        this.timerManager.clear();
        this.docker.removeRoom(this.roomId);
    }
    //广播游戏开始消息
    broadcastGameStart(){
        this.broadcastEvent('gameStart',{data:this.getMessage()});
    }
    //广播事件
    broadcastEvent(eventName,obj){
        if(this.isGameOver){
            return;
        }
        for(let i=0;i<this.users.length;i++){
            this.users[i].sendEvent(eventName,obj);
        }
    }
    //房间内广播消息
    broadcast(obj){
        if(this.isGameOver){
            return;
        }
        for(let i=0;i<this.users.length;i++){
            this.users[i].send(obj);
        }
    }
};

module.exports=Room;